package clientMain;

import java.util.ArrayList;
import java.util.Date;
import java.util.Timer;
import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.*;
import Tools.*;
import java.lang.StringBuffer;

/**
 * Generates clients
 * Stores important distributions for all clients
 * @author Andrew Fox
 *
 */

public class clientGenerator extends TimerTask{

	public static TreeMap<Double,Double> typingSpeedDist=new TreeMap<Double,Double>();
	public static TreeMap<Double,Double> typingErrorRate=new TreeMap<Double,Double>();
	public static TreeMap<Double,Double>clientsPer5s=new TreeMap<Double,Double>();
	static ArrayList<clientInfo>clients=new ArrayList<clientInfo>();
	static int delay;
	static ArrayList<clientInfo>activeClients=new ArrayList<clientInfo>();
	static ArrayList<clientInfo>inactiveClients=new ArrayList<clientInfo>();
	public static TreeMap<Double,Integer>numHeaderImages=new TreeMap<Double,Integer>();
	public static ArrayList<String>itemPics=new ArrayList<String>();
	public static TreeMap<Double,Integer>titleTotalWords=new TreeMap<Double,Integer>();
	public static TreeMap<Double,StringBuffer>titleWords=new TreeMap<Double,StringBuffer>();
	public static TreeMap<Double,Integer>itemSpecificsCat=new TreeMap<Double,Integer>();
	public static TreeMap<Double,StringBuffer>itemSpecificsCatWords=new TreeMap<Double,StringBuffer>();
	public static TreeMap<Double,Integer>itemSpecificsDesc=new TreeMap<Double,Integer>();
	public static TreeMap<Double,StringBuffer>itemSpecificsDescWords=new TreeMap<Double,StringBuffer>();
	public static TreeMap<Double,StringBuffer>maleFirstNames=new TreeMap<Double,StringBuffer>();
	public static TreeMap<Double,StringBuffer>femaleFirstNames=new TreeMap<Double,StringBuffer>();
	public static TreeMap<Double,StringBuffer>lastNames=new TreeMap<Double,StringBuffer>();
	public static TreeMap<Double,StringBuffer>streetNames=new TreeMap<Double,StringBuffer>();
	public static TreeMap<Double,StringBuffer>USStates=new TreeMap<Double,StringBuffer>();
	public static TreeMap<Double,StringBuffer>cities=new TreeMap<Double,StringBuffer>();
	public static TreeMap<String,StringBuffer>cityStates=new TreeMap<String,StringBuffer>();
	public static TreeMap<Double,StringBuffer>auctionType=new TreeMap<Double,StringBuffer>();
	public static TreeMap<Double,Double>buyNowPrice=new TreeMap<Double,Double>();
	public static TreeMap<Double,Double>buyNowPriceReverse=new TreeMap<Double,Double>();
	public static TreeMap<Double,Double>startingBid=new TreeMap<Double,Double>();
	public static double newClientProb=0.5;
	public static int count=0;
	public static Stats stats=new Stats();
	public static boolean verbose=runSettings.verbose;




	public class runClient extends TimerTask{
		clientInfo clientToRun=null;
		StringBuffer startPage=new StringBuffer(runSettings.rootURL).append("/login");
		public void run(){
			if(runSettings.HTML4==false)
				startPage=new StringBuffer(runSettings.rootURL).append("/index.html");
			if (clientToRun!=null){
				if(verbose)System.out.println("Starting Client: "+clientToRun.username);
				Client p;
				try {
					p = new Client(0.5,clientToRun,startPage);
					p.start();
				} catch (UnknownHostException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}

			}
		}
		public runClient(){
			if(Math.random()>newClientProb){
				if (inactiveClients.isEmpty()==false){
					int client=(int)Math.round(Math.random()*(inactiveClients.size()-1));
					this.clientToRun=inactiveClients.get(client);
					inactiveClients.remove(this.clientToRun);
					activeClients.add(this.clientToRun);
				}
			}
			else{
				this.clientToRun=new clientInfo();
				activeClients.add(this.clientToRun);
				startPage=new StringBuffer(runSettings.rootURL).append("/registeruser");

			}
		}
	}

	public void run(){
		Timer t2=new Timer();
		System.out.println("NUMBER OF ACTIVE CLIENTS: "+activeClients.size());
		count++;
		//		if (count>12)
		//			runSettings.meanClientsPerMinute=0;
		//		if (activeClients.size()>1000)
		//			if (activeClients.size()<2000)
		//				runSettings.meanClientsPerMinute=(2000-activeClients.size())*12;
		//			else
		//				runSettings.meanClientsPerMinute=0;
		if(activeClients.size()>=1)
			runSettings.meanClientsPerMinute=0;

		int numClientsInInterval=getPoisson(runSettings.meanClientsPerMinute/12);
		if(verbose)System.out.println("Number of Clients in these 5 seconds: "+numClientsInInterval);
		if (numClientsInInterval==0)
			delay=5000;
		else
			delay=5000/numClientsInInterval;
		Date now=new Date();
		for (int i=0;i<numClientsInInterval;i++){
			runClient rc=new runClient();
			t2.schedule(rc, new Date(now.getTime()+delay*i));
		}

	}

	public clientGenerator(){

	}




	public static void main(String[] args) throws IOException{


		initializeDistributions();

		if(runSettings.HTML4==true){
			clientInfo Kim1=new clientInfo(new StringBuffer("User2"),new StringBuffer("User2"));
			clientInfo Kim2=new clientInfo(new StringBuffer("User3"),new StringBuffer("User3"));
			clientInfo Kim3=new clientInfo(new StringBuffer("User4"),new StringBuffer("User4"));
			clientInfo Kim4=new clientInfo(new StringBuffer("User5"),new StringBuffer("User5"));
			clientInfo Kim5=new clientInfo(new StringBuffer("User6"),new StringBuffer("User6"));
			clientInfo Kim6=new clientInfo(new StringBuffer("User7"),new StringBuffer("User7"));
			clientInfo Kim7=new clientInfo(new StringBuffer("RUTHWADE6312"),new StringBuffer("L(|#qYC9IxtZ"));
			clientInfo Kim8=new clientInfo(new StringBuffer("AMANDAMORRIS8820"),new StringBuffer("g)p[j3s="));
			clientInfo Kim9=new clientInfo(new StringBuffer("NOELOLSON2847"),new StringBuffer("Lb0IgLD$"));
			clientInfo Kim10=new clientInfo(new StringBuffer("RONALDVERDIER3649"),new StringBuffer("Xs"));
			clients.add(Kim1);
			inactiveClients.add(Kim1);
			clients.add(Kim2);
			inactiveClients.add(Kim2);
			clients.add(Kim3);
			inactiveClients.add(Kim3);
			clients.add(Kim4);
			inactiveClients.add(Kim4);
			clients.add(Kim5);
			inactiveClients.add(Kim5);
			clients.add(Kim6);
			inactiveClients.add(Kim6);
			clients.add(Kim7);
			inactiveClients.add(Kim7);
			clients.add(Kim8);
			inactiveClients.add(Kim8);
			clients.add(Kim9);
			inactiveClients.add(Kim9);
			clients.add(Kim10);
			inactiveClients.add(Kim10);
		}
		else{
			clientInfo user1=new clientInfo(new StringBuffer("johnpayn"),new StringBuffer("temp4now"));
			clients.add(user1);
			inactiveClients.add(user1);
		}

		stats.start();

		Timer t1=new Timer();
		clientGenerator cg=new clientGenerator();
		t1.schedule(cg, 0, 5000);

		//		for (int i=0;i<3;i++){
		//			Client p=new Client(0.5,clients.get(i),"http://10.9.77.3:8080/cmubis-0.1/login");
		//			p.start();
		//		}
		while(true){
			int numClientsInInterval=getPoisson(runSettings.meanClientsPerMinute/12);
			if (numClientsInInterval==0)
				delay=5000;
			else
				delay=5000/numClientsInInterval;
		}



	}


	public static void initializeDistributions() throws IOException{
		//Item Pictures
		loadItemImages();

		// Typing Speed Average
		typingSpeedDist.put(100.0, 695.);
		typingSpeedDist.put(99.98, 685.);
		typingSpeedDist.put(99.96, 675.);
		typingSpeedDist.put(99.94, 665.);
		typingSpeedDist.put(99.92, 655.);
		typingSpeedDist.put(99.90, 645.);
		typingSpeedDist.put(99.88, 635.);
		typingSpeedDist.put(99.85, 625.);
		typingSpeedDist.put(99.81, 615.);
		typingSpeedDist.put(99.76, 605.);
		typingSpeedDist.put(99.70, 595.);
		typingSpeedDist.put(99.63, 585.);
		typingSpeedDist.put(99.55, 575.);
		typingSpeedDist.put(99.46, 565.);
		typingSpeedDist.put(99.36, 555.);
		typingSpeedDist.put(99.21, 545.);
		typingSpeedDist.put(99.06, 535.);
		typingSpeedDist.put(98.86, 525.);
		typingSpeedDist.put(98.56, 515.);
		typingSpeedDist.put(98.26, 505.);
		typingSpeedDist.put(97.91, 495.);
		typingSpeedDist.put(97.51, 485.);
		typingSpeedDist.put(97.01, 475.);
		typingSpeedDist.put(96.46, 465.);
		typingSpeedDist.put(95.86, 455.);
		typingSpeedDist.put(95.16, 445.);
		typingSpeedDist.put(94.41, 435.);
		typingSpeedDist.put(93.61, 425.);
		typingSpeedDist.put(92.76, 415.);
		typingSpeedDist.put(91.86, 405.);
		typingSpeedDist.put(90.86, 395.);
		typingSpeedDist.put(89.86, 385.);
		typingSpeedDist.put(88.66, 375.);
		typingSpeedDist.put(87.46, 365.);
		typingSpeedDist.put(86.16, 355.);
		typingSpeedDist.put(84.66, 345.);
		typingSpeedDist.put(83.16, 335.);
		typingSpeedDist.put(81.48, 325.);
		typingSpeedDist.put(79.8, 315.);
		typingSpeedDist.put(78.1, 305.);
		typingSpeedDist.put(76.3, 295.);
		typingSpeedDist.put(74.3, 285.);
		typingSpeedDist.put(72.2, 275.);
		typingSpeedDist.put(69.9, 265.);
		typingSpeedDist.put(67.4, 255.);
		typingSpeedDist.put(64.6, 245.);
		typingSpeedDist.put(61.5, 235.);
		typingSpeedDist.put(58.2, 225.);
		typingSpeedDist.put(54.7, 215.);
		typingSpeedDist.put(51.0, 205.);
		typingSpeedDist.put(47.0, 195.);
		typingSpeedDist.put(42.8, 185.);
		typingSpeedDist.put(38.3, 175.);
		typingSpeedDist.put(33.5, 165.);
		typingSpeedDist.put(28.63, 155.);
		typingSpeedDist.put(23.73, 145.);
		typingSpeedDist.put(19.03, 135.);
		typingSpeedDist.put(14.73, 125.);
		typingSpeedDist.put(11.03, 115.);
		typingSpeedDist.put(8.13, 105.);
		typingSpeedDist.put(5.83, 95.);
		typingSpeedDist.put(4.13, 85.);
		typingSpeedDist.put(2.73, 75.);
		typingSpeedDist.put(1.63, 65.);
		typingSpeedDist.put(0.83, 55.);
		typingSpeedDist.put(0.33, 45.);
		typingSpeedDist.put(0.13, 35.);
		typingSpeedDist.put(0.08, 25.);

		// Typing Error Rate
		typingErrorRate.put(108.*5,0.04);
		typingErrorRate.put(63.*5,0.041);
		typingErrorRate.put(55.*5,0.044);
		typingErrorRate.put(48.*5,0.05);
		typingErrorRate.put(43.*5,0.055);
		typingErrorRate.put(37.*5,0.053);
		typingErrorRate.put(33.*5,0.058);
		typingErrorRate.put(29.*5,0.057);
		typingErrorRate.put(25.*5,0.06);
		typingErrorRate.put(20.*5,0.075);


		numHeaderImages=loadCSV_DI("numHeaderImages");
		titleTotalWords=loadCSV_DI("titleTotalWords");
		itemSpecificsCat=loadCSV_DI("itemSpecificsNumCategories");
		itemSpecificsDesc=loadCSV_DI("itemSpecificsDescriptionTotal");
		titleWords=loadCSV_DS("titleWordCount");
		itemSpecificsCatWords=loadCSV_DS("itemSpecificsCategoriesWords");
		itemSpecificsDescWords=loadCSV_DS("itemSpecificsDescriptionWords");
		maleFirstNames=loadCSV_DS("malefirstnames");
		femaleFirstNames=loadCSV_DS("femalefirstnames");
		lastNames=loadCSV_DS("lastnames");
		streetNames=loadCSV_DS("streetNames");
		USStates=loadCSV_DS("USStateCount");
		cities=loadCSV_DS("cities");
		cityStates=loadCSV_SS("citystates");
		auctionType=loadCSV_DS("auctionType");
		buyNowPrice=loadCSV_DD("buyNowPrice");
		buyNowPriceReverse=reverseMap_DD(buyNowPrice);
		startingBid=loadCSV_DD("startingBid");

	}

	public static int getPoisson(double mean){
		double L=Math.exp(-mean);
		int k=0;
		double p=1;
		do{
			k+=1;
			p*=Math.random();
		}while(p>L);
		return (k-1);
	}

	public static TreeMap<Double,Integer> loadCSV_DI(String file) throws IOException{
		TreeMap<Double,Integer> map=new TreeMap<Double,Integer>();
		TreeMap<Double,Integer> map2=new TreeMap<Double,Integer>();
		Double probSum=0.;
		FileReader fstream = new FileReader(runSettings.srcFolder+file+".csv");
		BufferedReader in = new BufferedReader(fstream);

		String s;
		while((s=in.readLine())!=null){
			int commaIndex=s.indexOf(',');
			Integer value=Integer.parseInt(s.substring(0,commaIndex));
			Double key=Double.parseDouble(s.substring(commaIndex+1));
			probSum+=key;
			map.put(probSum, value);
		}
		//normalization
		double prevValue=0.;
		for (double m:map.keySet()){
			map2.put(1-prevValue,map.get(m));
			prevValue=m/probSum;
		}

		in.close();
		return map2;
	}

	public static TreeMap<Double,Double> loadCSV_DD(String file) throws IOException{
		TreeMap<Double,Double> map=new TreeMap<Double,Double>();
		TreeMap<Double,Double> map2=new TreeMap<Double,Double>();
		Double probSum=0.;
		FileReader fstream = new FileReader(runSettings.srcFolder+file+".csv");
		BufferedReader in = new BufferedReader(fstream);

		String s;
		while((s=in.readLine())!=null){
			int commaIndex=s.indexOf(',');
			Double value=Double.parseDouble(s.substring(0,commaIndex));
			Double key=Double.parseDouble(s.substring(commaIndex+1));
			probSum+=key;
			map.put(probSum, value);
		}
		//normalization
		double prevValue=0.;
		for (double m:map.keySet()){
			map2.put(1-prevValue,map.get(m));
			prevValue=m/probSum;
		}

		in.close();
		return map2;
	}

	public static TreeMap<Double,StringBuffer> loadCSV_DS(String file) throws IOException{
		TreeMap<Double,StringBuffer> map=new TreeMap<Double,StringBuffer>();
		TreeMap<Double,StringBuffer> map2=new TreeMap<Double,StringBuffer>();
		Double probSum=0.;
		FileReader fstream = new FileReader(runSettings.srcFolder+file+".csv");
		BufferedReader in = new BufferedReader(fstream);

		String s;
		while((s=in.readLine())!=null){
			int commaIndex=s.indexOf(',');
			StringBuffer value=new StringBuffer(s.substring(0,commaIndex));
			Double key=Double.parseDouble(s.substring(commaIndex+1));
			probSum+=key;
			map.put(probSum, value);
		}
		//normalization
		double prevValue=0.;
		for (double m:map.keySet()){
			map2.put(1-prevValue,map.get(m));
			prevValue=m/probSum;
		}

		in.close();
		return map2;
	}

	public static TreeMap<String,StringBuffer> loadCSV_SS(String file) throws IOException{
		TreeMap<String,StringBuffer> map=new TreeMap<String,StringBuffer>();
		FileReader fstream = new FileReader(runSettings.srcFolder+file+".csv");
		BufferedReader in = new BufferedReader(fstream);
		String s;
		while((s=(in.readLine()))!=null){
			int commaIndex=s.indexOf(",");
			String key=s.substring(0,commaIndex);
			StringBuffer value=new StringBuffer(s.substring(commaIndex+1,s.length()));
			map.put(key, value);
		}

		in.close();
		return map;
	}

	public static TreeMap<Double,Double> reverseMap_DD(TreeMap<Double,Double> map1){
		TreeMap<Double,Double> map2=new TreeMap<Double,Double>();
		for (double m:map1.keySet()){
			map2.put(map1.get(m), m);
		}

		return map2;
	}

	public static void loadItemImages() throws IOException{
		FileReader fstream = new FileReader(runSettings.srcFolder+"itemImages.csv");
		BufferedReader in = new BufferedReader(fstream);

		String s;
		while((s=in.readLine())!=null){
			itemPics.add(runSettings.srcFolder+"Sample Pictures\\"+s+".jpg");
		}
		in.close();
	}

}
